using System;
using System.Linq;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.Metadata.Entity.DataModel;

namespace T.FAS.Runtime.DataAccess.Common
{
    /// <summary>
    /// TRecord扩展方法
    /// </summary>
    public static class TRecordCommonExtension
    {
        private static readonly IDACLogService _localLogService = DACLogFactory.GetDACLogService();
        /// <summary>
        /// 填充TRecord.PKColumnName属性
        /// </summary>
        /// <param name="record"></param>
        /// <param name="cno"></param>
        /// <returns></returns>
        public static TRecord FillPkColumn(this TRecord record, CompositeNodeObject cno)
        {
            if (cno == null)
                throw new FasException(DataAccessErrorCode.NullValue, nameof(cno));
            string pkColumnName = cno.GetPKColumnForEngine().ColumnName;
            record.PKColumnName = pkColumnName;
            record.TimestampColumnName = cno.GetTimestampColumnForEngine()?.ColumnName;
            return record;
        }

        /// <summary>
        /// 获取当前节点的主键val
        /// </summary>
        /// <param name="record"></param>
        /// <param name="cno"></param>
        /// <returns></returns>
        public static string GetPKValue(this TRecord record, CompositeNodeObject cno)
        {
            try
            {
                var pkCol = cno.DataObject.Columns.FirstOrDefault(c => c.IsPkColumn);
                if (pkCol == null)
                    throw new FasException(DataAccessErrorCode.CompositeDataObject.Error, string.Format(CommonStringClassCommon.TRecordCommonExtension_CNOGetPKValueFail,cno.CompositeDataObject?.Code,cno.DataObjectTableAlias));
                var pkVal = record.GetValue(pkCol.ColumnName);
                if (pkVal == null)
                    throw new FasException(DataAccessErrorCode.CompositeDataObject.Error, string.Format(CommonStringClassCommon.TRecordCommonExtension_TRecordGetPkColumnFail,cno.CompositeDataObject?.Code,cno.DataObjectTableAlias));
                return pkVal.ToString();
            }
            catch (Exception e)
            {
                throw new Exception(CommonStringClassCommon.TRecordCommonExtension_TRecordGetPKValueFail, e);
            }
        }

        /// <summary>
        /// 获取当前节点的主键val
        /// </summary>
        /// <param name="record"></param>
        /// <param name="cdo"></param>
        /// <returns></returns>
        public static string GetPKValue(this TRecord record, CompositeDataObject cdo, bool isThrowException = true)
        {
            try
            {
                var pkCol = cdo.RootCompositeNodeObject.DataObject.Columns.FirstOrDefault(c => c.IsPkColumn);
                if (pkCol == null)
                {
                    if (isThrowException)
                        throw new FasException(DataAccessErrorCode.CompositeDataObject.Error, string.Format(CommonStringClassCommon.TRecordCommonExtension_GetPKValue3, cdo?.Code));
                }
                var pkVal = record.GetValue(pkCol.ColumnName);
                if (pkVal == null)
                {
                    if (isThrowException)
                        throw new FasException(DataAccessErrorCode.CompositeDataObject.Error, string.Format(CommonStringClassCommon.TRecordCommonExtension_GetPKValue4,cdo?.Code));
                }
                return pkVal.ToString();
            }
            catch (Exception e)
            {
                if (isThrowException)
                    throw new Exception(CommonStringClassCommon.TRecordCommonExtension_TRecordGetPKValueFail, e);
                _localLogService.WriteError(e);
            }
            return null;
        }

        /// <summary>
        /// 获取当前节点的主键val
        /// </summary>
        /// <param name="record"></param>
        /// <param name="cno"></param>
        /// <returns></returns>
        public static object GetValue(this TRecord record, CompositeNodeObjectElement ele)
        {
            try
            {
                var pkCol = ele.DataColumn;
                if (pkCol == null)
                    throw new FasException(DataAccessErrorCode.CompositeDataObject.Error, string.Format(CommonStringClassCommon.TRecordCommonExtension_GetValue,ele.CompositeDataObjectID,ele.CompositeNodeObjectID,ele.Alias));
                return record.GetRecordValue(pkCol.ColumnName);
            }
            catch (Exception e)
            {
                throw new FasException(DataAccessErrorCode.CompositeDataObject.Error, string.Format(CommonStringClassCommon.TRecordCommonExtension_TRecordGetSpecifiedAttrValueFail), e);
            }
        }

        /// <summary>
        /// 获取Record指定属性值
        /// </summary>
        /// <param name="record"></param>
        /// <param name="AttrName"></param>
        /// <returns></returns>
        public static object GetRecordValue(this TRecord record, string AttrName)
        {
            try
            {
                if (!record.IsContainProperty(AttrName))
                    throw new FasException(DataAccessErrorCode.CompositeDataObject.Error, string.Format(CommonStringClassCommon.TRecordCommonExtension_GetRecordValue,AttrName));
                var pkVal = record.GetValue(AttrName);
                return pkVal;
            }
            catch (Exception e)
            {
                throw new FasException(DataAccessErrorCode.CompositeDataObject.Error, string.Format(CommonStringClassCommon.TRecordCommonExtension_TRecordGetSpecifiedAttrValueFail), e);
            }
        }

        /// <summary>
        /// 克隆
        /// </summary>
        /// <param name="set"></param>
        /// <returns></returns>
        public static TChangeLog DACCloneChangeSet(this TChangeLog set)
        {
            TChangeLog changeSet = new TChangeLog(set.DataChangeType, set.Modifier, set.ModifyTime);
            changeSet.CDOCode = set.CDOCode;
            changeSet.CDOName = set.CDOName;
            changeSet.BillID = set.BillID;
            changeSet.DataChangeType = set.DataChangeType;
            changeSet.Modifier = set.Modifier;
            changeSet.CDOID = set.CDOID;
            changeSet.TenantID = set.TenantID;
            changeSet.CDOCode = set.CDOCode;
            changeSet.CDOName = set.CDOName;
            changeSet.ModifierName = set.ModifierName;
            return changeSet;
        }

        /// <summary>
        /// 获取TRecord对应的CDO的主节点的主键列的值
        /// </summary>
        /// <param name="record"></param>
        /// <param name="compositeDataObject"></param>
        /// <returns></returns>
        public static string GetCDOTRecordPrimaryKeyValue(this TRecord record, CompositeDataObject compositeDataObject)
        {
            try
            {
                var pkCol = compositeDataObject.RootCompositeNodeObject?.DataObject.Columns.FirstOrDefault(c => c.IsPkColumn);
                if (pkCol == null)
                    throw new FasException(DataAccessErrorCode.CompositeDataObject.Error, string.Format(CommonStringClassCommon.TRecordCommonExtension_GetCDOTRecordPrimaryKeyValue,compositeDataObject.Code));
                var pkVal = record.GetValue(pkCol.ColumnName);
                if (pkVal == null)
                    throw new FasException(DataAccessErrorCode.CompositeDataObject.Error, string.Format(CommonStringClassCommon.TRecordCommonExtension_GetCDOTRecordPrimaryKeyValue1,compositeDataObject.Code));
                return pkVal.ToString();
            }
            catch (Exception e)
            {
                throw new Exception(CommonStringClassCommon.TRecordCommonExtension_TRecordGetPKValueFail, e);
            }
        }

        /// <summary>
        /// 获取TRecord指定属性值，特殊处理特殊类型
        /// </summary>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public static object GetValueForDAC(this TRecord record, string propertyName)
        {
            var val = record.GetValue(propertyName);
            val = AbstractDataTypeTool.ProcessSpecialObject(val);
            return val;
        }
    }
}
